package textBuddyProcessor;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.Vector;

/*
 * ==============NOTE TO USER==========================================
 * This class is the CPU of TextBuddy, it carries on the complete processing
 * Add, Delete, Display, Clear, Undo, Search and Sort.
 * ====================================================================
 */

public class ControllerLogic {
	private static final String MESSAGE_ADD = "added to %1$s : \"%2$s\"";
	private static final String MESSAGE_DELETE = "deleted from %1$s :\"%2$s\"";
	private static final String MESSAGE_CLEAR = "all content cleared from %1$s";
	private static final String MESSAGE_DISPLAY = "%1$s is empty";
	private static final String MESSAGE_NOT_FOUND = "%1$s is not found or does not exist";
	private static final String MESSAGE_UNSUCCESFUL = "Sorry not found in file";
	private static final String MESSAGE_SORTED = "Already Sorted";
	private static final String TEMP_FILE = "temp.txt";
	private static final String DEL_BEG = "0";
	private static final int EMPTY = 0;
	private static final String PREV_VERSION_FILE = "previousVersion.txt";

	private static final String MESSAGE_INVALID_DELETE = "%2$s cannot be found in %1$s";
	private static final String MESSAGE_CANNOT_PRINT = "The data was displayed!! "
			+ "The command befor Display was undone ";
	private static final String MESSAGE_UNDONE = "The last change was undone";
	private static final String MESSAGE_WRONG_COMMAND = "Invalid Command, Press h/H for help or"
			+ " enter the valid command";
	private static final String MESSAGE_TO_SORT = "Please enter the way you want to sort A = Ascending,"
			+ "D = Descending";
	private static final String MESSAGE_TO_SEARCH = "Please enter the string or number you want to search for";

	private static final String COMMANDS_DISPLAY = "Commands are 1. add <text>"
			+ " 2. display 3. Delete <number>  4. Clear 5. Undo  6. Sort ";

	private static final String COMMAND_EXIT = "exit";
	private static final String COMMAND_HELP = "h";
	private static final String COMMAND_ASCENDING = "A";
	private static final String COMMAND_DESCENDING = "D";

	private static final int SPLIT_PARAM = 2; // to split the string into 2
	// after first space
	private static final int SPACE_ADD = 5; // to check if add is followed by
	// something
	private static final int SPACE_DELETE = 7; // to check if delete is followed
	// by a number
	private static final String COMMAND_DISPLAY = "DISPLAY";

	// enum to store the command types and use switch
	enum COMMAND_TYPE {
		ADD, DELETE, CLEAR, EXIT, SORT, SEARCH, UNDO, DISPLAY, INVALID;
	}

	private String userFileName;
	private FileWriter writerToFile;
	private FileReader readerFromFile;
	private File temporaryFile;
	private String originalFileName;
	private static int numberOfElementsInFile = 0;
	private File previousVersionFile;
	public Vector<String> sortedVector = new Vector<String>();
	public String userInput;

	int getValueOfCountIfFileExisted() {
		BufferedReader bufferReaderToFile = null;
		if (this.getExistingFile().exists()) {
			try {
				bufferReaderToFile = new BufferedReader(new FileReader(
						userFileName));
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
				System.out.println(MESSAGE_NOT_FOUND);
			}
			try {

				while (bufferReaderToFile.readLine() != null) {
					setNumberOfElementsInFile(getNumberOfElementsInFile() + 1);
				}
			} catch (IOException e) {
				e.printStackTrace();
				System.out.println(String.format(MESSAGE_NOT_FOUND,
						this.getFileName()));
			}
		}
		return numberOfElementsInFile;
	}

	public FileWriter getWriterFromFile() {
		return writerToFile;
	}

	public void setWriterToFile(FileWriter writeToFile) {
		this.writerToFile = writeToFile;
	}

	public String getFileName() {
		return userFileName;
	}

	public void setFileName(String fileName) {
		this.userFileName = fileName;
	}

	public FileReader getReaderToFile() {
		return readerFromFile;
	}

	public void setReaderToFile(FileReader readFromFile) {
		this.readerFromFile = readFromFile;
	}

	public File getExistingFile() {
		return temporaryFile;
	}

	public void setExistingFile(File temporaryFileName) {
		this.temporaryFile = temporaryFileName;
	}

	void addContentToFile(String stringToAdd, boolean isClearedBeforeWriting)
			throws IOException {
		setWriterToFile(new FileWriter(this.getFileName(),
				isClearedBeforeWriting));
		setNumberOfElementsInFile(getNumberOfElementsInFile() + 1);
		writerToFile.write(getNumberOfElementsInFile() + ". " + stringToAdd
				+ "\n");
		getWriterFromFile().close();
		if (this.getFileName().equals(originalFileName))
			System.out.println(String.format(MESSAGE_ADD, this.getFileName(),
					stringToAdd));

	}

	void deleteFromFile(String stringToDelete) throws IOException {
		checkIfRowExists(stringToDelete);
		setNumberOfElementsInFile(0);
		ControllerLogic deleteLogic = new ControllerLogic();
		createTemporaryFile(deleteLogic);
		addExistingValuesExceptDelValue(deleteLogic, stringToDelete);
		renameOrginialFile(deleteLogic);
	}

	private void checkIfRowExists(String stringToDelete) {
		if (Integer.parseInt(stringToDelete) > getNumberOfElementsInFile()) {
			System.out.println(String.format(MESSAGE_INVALID_DELETE,
					this.getFileName(), stringToDelete));
		}
	}

	private void renameOrginialFile(ControllerLogic deleteLogic) {
		deleteLogic.temporaryFile.renameTo(this.getExistingFile());
	}

	private void addExistingValuesExceptDelValue(ControllerLogic deleteLogic,
			String stringToDelete) throws IOException {
		BufferedReader bufferReaderToFile = null;
		String fileContent = null;
		String deletedContent = null;
		try {
			bufferReaderToFile = new BufferedReader(new FileReader(
					this.getFileName()));
		} catch (FileNotFoundException e1) {
			System.out.println(MESSAGE_NOT_FOUND);
		}
		try {
			while ((fileContent = bufferReaderToFile.readLine()) != null) {
				if (fileContent.startsWith(stringToDelete)) {
					deletedContent = fileContent.substring(2);
				} else {
					deleteLogic
							.addContentToFile(fileContent.substring(3), true);
				}
			}
		} catch (IOException e) {
			System.out.println(String.format(MESSAGE_CLEAR));
		}
		bufferReaderToFile.close();
		if (this.getFileName().equals(originalFileName)
				&& deletedContent != null) {
			System.out.println(String.format(MESSAGE_DELETE,
					this.getFileName(), deletedContent));
		}
	}

	private void createTemporaryFile(ControllerLogic deleteLogic)
			throws IOException {
		deleteLogic.setExistingFile(new File(TEMP_FILE));
		deleteLogic.setFileName(TEMP_FILE);
		deleteLogic.getExistingFile().createNewFile();
	}

	String[] displayContentsOfFile() throws IOException {
		// Reading from file
		BufferedReader bufferReaderToFile = null;
		String arrayToStoreTestCases[] = null;
		try {
			bufferReaderToFile = new BufferedReader(
					new FileReader(userFileName));
			arrayToStoreTestCases = readFromFile(bufferReaderToFile);
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
			System.out.println(MESSAGE_NOT_FOUND);
		}

		bufferReaderToFile.close();
		return arrayToStoreTestCases;
	}

	public String[] readFromFile(BufferedReader bufferReaderToFile) {
		String paramFromFile = null;
		checkIfEmpty();
		String arrayToStoreTestCases[] = new String[ControllerLogic
				.getNumberOfElementsInFile()];
		int i = 0;
		try {
			while ((paramFromFile = bufferReaderToFile.readLine()) != null) {
				System.out.println(paramFromFile);
				arrayToStoreTestCases[i++] = (paramFromFile);
				// for testing purposes:
			}
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println(MESSAGE_NOT_FOUND);
		}
		return arrayToStoreTestCases;
	}

	boolean checkIfEmpty() {
		if (this.getExistingFile().length() == 0) {
			System.out.println(String.format(MESSAGE_DISPLAY,
					this.getFileName()));
			return true;
		}
		return false;
	}

	void performOperationAsInput(String userOption,
			BufferedReader bufferReaderForInput) throws IOException {

		userOption = userOption.trim();
		// to get the command and content separately
		String[] tempCmd = userOption.split(" ", SPLIT_PARAM);
		// to allow command to be entered in any case
		COMMAND_TYPE userCmd = null;
		try {
			userCmd = COMMAND_TYPE.valueOf(tempCmd[0].toUpperCase());
		} catch (IllegalArgumentException e) {
			userCmd = COMMAND_TYPE.INVALID;
		}
		System.out.println("command :" + userOption);
		switch (userCmd) {
		case ADD:
			if (userOption.length() >= SPACE_ADD) {
				savePreviousVersionOfFile();
				addContentToFile(userOption.substring(SPACE_ADD - 1), true);
			}
			break;
		case DISPLAY:
			displayContentsOfFile();
			break;
		case DELETE:
			if (userOption.length() >= SPACE_DELETE) {
				savePreviousVersionOfFile();
				deleteFromFile(userOption.substring(SPACE_DELETE));
			}
			break;
		case CLEAR:
			savePreviousVersionOfFile();
			clearFromFile(this.getExistingFile());
			break;
		case UNDO:
			undoLastAction(userOption);
			break;
		case SORT:
			savePreviousVersionOfFile();
			System.out.println(MESSAGE_TO_SORT);
			String askOption = COMMAND_ASCENDING;
			askOption = askForOption(bufferReaderForInput);
			sortFileAlphabetically(askOption);
			break;
		case SEARCH:
			if (userOption.length() <= 6) {
				inputParamToSearch();
			} else {
				userInput = userOption.substring(7);
				searchIfElementExists();
			}

			break;
		default:
			System.out.println(String.format(MESSAGE_WRONG_COMMAND));
			break;
		}

	}

	public void inputParamToSearch() throws IOException {
		System.out.println(MESSAGE_TO_SEARCH);
		BufferedReader bufferReaderFor = new BufferedReader(
				new InputStreamReader(System.in));
		userInput = bufferReaderFor.readLine();
		searchIfElementExists();
	}

	public void searchIfElementExists() {
		sortedVector.clear();
		BufferedReader bufferReadertoSearch = null;
		try {
			bufferReadertoSearch = new BufferedReader(new FileReader(
					userFileName));
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
			System.out.println(MESSAGE_NOT_FOUND);
		}
		String temporaryVal1 = null;
		String temporaryVal2 = null;
		int counter = 0;
		String userInputTemp = userInput.toLowerCase();
		for (int i = 1; i <= getNumberOfElementsInFile(); i++) {
			try {
				temporaryVal1 = bufferReadertoSearch.readLine();
				temporaryVal2 = temporaryVal1.toLowerCase();
			} catch (IOException e1) {
				e1.printStackTrace();
				System.out.println(String.format(MESSAGE_DISPLAY,
						this.getFileName()));
			}
			if (temporaryVal2.toLowerCase().contains(userInputTemp)) {
				sortedVector.add(temporaryVal1);
				System.out.println(sortedVector.elementAt(counter));
				counter++;
			}
		}
		if (sortedVector.isEmpty()) {
			System.out.println(MESSAGE_UNSUCCESFUL);
		}
	}

	private String askForOption(BufferedReader bufferReaderForInput)
			throws IOException {
		String userCommand = bufferReaderForInput.readLine();
		return userCommand;
	}

	void sortFileAlphabetically(String userOption) throws IOException {

		sortedVector.clear();
		BufferedReader bufferReader = addBufferReaderToFile();
		if (getNumberOfElementsInFile() > 0) {
			boolean isSorted = checkIfSorted(bufferReader, userOption);
			bufferReader.close();
			if (isSorted == false) {
				sortAccorToOption(userOption);
				writeToFileFromVector();
			} else {
				System.out.println(MESSAGE_SORTED);
			}
		} else {
			System.out.println(String.format(MESSAGE_DISPLAY,
					this.getFileName()));
		}
		bufferReader.close();
	}

	private void writeToFileFromVector() throws IOException {
		clearFromFile(this.getExistingFile());
		for (int i = 0; i < sortedVector.size(); i++) {
			String temp = sortedVector.elementAt(i);
			addContentToFile(temp, true);
		}

	}

	private void sortAccorToOption(String userOption) {
		boolean isDiff = false;
		for (int i = 1; i < sortedVector.size(); i++) {
			int j = i;
			// to store the content of vector
			String tempVar = sortedVector.elementAt(i);
			if (userOption.equals(COMMAND_DESCENDING)) {
				isDiff = (sortedVector.elementAt(j - 1).compareToIgnoreCase(
						tempVar) < 0);
			} else {
				isDiff = (sortedVector.elementAt(j - 1).compareToIgnoreCase(
						tempVar) > 0);
			}
			while ((j > 0) && isDiff) {

				sortedVector.remove(j);
				sortedVector.add(j, sortedVector.elementAt(j - 1));
				j--;
				if (j >= 1) {
					if (userOption.equals(COMMAND_DESCENDING)) {
						isDiff = (sortedVector.elementAt(j - 1)
								.compareToIgnoreCase(tempVar) < 0);
					} else {
						isDiff = (sortedVector.elementAt(j - 1)
								.compareToIgnoreCase(tempVar) > 0);
					}
				}
			}
			sortedVector.remove(j);
			sortedVector.add(j, tempVar);
		}

	}

	private boolean checkIfSorted(BufferedReader bufferReaderToFile,
			String userOption) throws IOException {
		boolean isSorted = false;
		String firstTempVar, secondTempVar;
		int tempCount = getNumberOfElementsInFile();
		for (int i = 1; i <= tempCount; i++) {
			firstTempVar = bufferReaderToFile.readLine();
			sortedVector.add(firstTempVar.substring(3));
			System.out.println(sortedVector.elementAt(i - 1));
		}
		int i = 0;
		while (tempCount > 1) {
			firstTempVar = sortedVector.elementAt(i);
			secondTempVar = sortedVector.elementAt(i + 1);
			if (firstTempVar.compareToIgnoreCase(secondTempVar) <= 0
					&& userOption.compareToIgnoreCase(COMMAND_ASCENDING) == 0) {
				isSorted = true;
			} else if (firstTempVar.compareToIgnoreCase(secondTempVar) >= 0
					&& userOption.compareToIgnoreCase(COMMAND_DESCENDING) == 0) {
				isSorted = true;
			} else {
				isSorted = false;
			}
			if (isSorted != true)
				return isSorted;
			tempCount--;
			i++;
		}

		return isSorted;
	}

	private BufferedReader addBufferReaderToFile() throws IOException {
		BufferedReader bufferReaderToFile = null;
		try {
			bufferReaderToFile = new BufferedReader(new FileReader(
					this.userFileName));
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
			System.out.println(MESSAGE_NOT_FOUND);
		}
		return bufferReaderToFile;

	}

	private void savePreviousVersionOfFile() throws IOException {
		setNumberOfElementsInFile(EMPTY);
		previousVersionFile = new File(PREV_VERSION_FILE);
		previousVersionFile.createNewFile();
		ControllerLogic previousLogic = new ControllerLogic();
		previousLogic.setExistingFile(previousVersionFile);
		previousLogic.setFileName(PREV_VERSION_FILE);
		clearFromFile(previousVersionFile);
		addExistingValuesExceptDelValue(previousLogic, DEL_BEG);
	}

	private void undoLastAction(String s) throws IOException {
		if (s.startsWith(COMMAND_DISPLAY)) {
			printInabilityToDo();
		} else {
			previousVersionFile.renameTo(this.getExistingFile());
			System.out.println(String.format(MESSAGE_UNDONE));
		}

	}

	private void printInabilityToDo() {
		System.out.println(String.format(MESSAGE_CANNOT_PRINT));

	}

	public void clearFromFile(File file) throws IOException {

		FileWriter erasor = new FileWriter(file);
		erasor.write("");
		setNumberOfElementsInFile(0);
		erasor.close();
		if (file.equals(this.getExistingFile()))
			System.out.println(String.format(MESSAGE_CLEAR, this.userFileName));
	}

	public void executeCommandsUntilExitCommand(Scanner s) throws IOException {

		this.getValueOfCountIfFileExisted();
		originalFileName = this.getFileName();
		BufferedReader bufferedReaderForUSerInput = new BufferedReader(
				new InputStreamReader(System.in));
		String wr = null;
		do {
			wr = bufferedReaderForUSerInput.readLine();
			if (!wr.equals(COMMAND_EXIT)) {
				if (wr.equalsIgnoreCase(COMMAND_HELP)) {
					System.out.println(String.format(COMMANDS_DISPLAY));
					continue;
				}
				this.performOperationAsInput(wr, bufferedReaderForUSerInput);
			}

		} while (!wr.equals(COMMAND_EXIT));
		bufferedReaderForUSerInput.close();
	}

	public static int getNumberOfElementsInFile() {
		return numberOfElementsInFile;
	}

	public static void setNumberOfElementsInFile(int numberOfElementsInFile) {
		ControllerLogic.numberOfElementsInFile = numberOfElementsInFile;
	}
}
